package com.katesoft.scale4j.common.utils;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * @author kate2007
 */
public final class ReflectionUtility {
   /**
    * Return actual parameter type for generic subclass or interface.
    * <p/>
    * Note:
    * <p/>
    * 1)this method assume that given class is parameterized subclass(interface) and parent class is
    * not {@link Object} so may cause {@link NullPointerException} at runtime.
    * <p/>
    * 2)this method assume that genericSuperClass is ParameterizedType and even does not validate it
    * so may produce {@link ClassCastException} at runtime.
    * <p/>
    * 3)this method assume that given index is valid so may produce
    * {@link IndexOutOfBoundsException} at runtime.
    * 
    * @param clazz
    *           target class
    * @param index
    *           position of type.
    * @return actual parameterized type.
    */
   public static Class<?> getActualGenericType(final Class<?> clazz, final int index) {
      if (clazz.isInterface()) {
         for (final Type type : clazz.getGenericInterfaces()) {
            if (type instanceof ParameterizedType) {
               return (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[index];
            }
         }
      }
      return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[index];
   }

   /**
    * Build method signature and return human readable simplified signature.
    * <p/>
    * For example method
    * <code>void foo(java.land.String s, com.katesoft.jvmcluster.persistent.User)</code> will have
    * signature like this <code>foo(String, User)</code>.
    * 
    * @param m
    *           target method.
    * @return simplified signature of the given method.
    */
   public static String buildMethodSignature(final Method m) {
      final StringBuilder args = new StringBuilder();
      for (@SuppressWarnings("rawtypes")
      final Class i : m.getParameterTypes()) {
         if (args.length() > 0) {
            args.append(",");
         }
         args.append(i != null ? i.getSimpleName() : null);
      }
      return m.getName() + "(" + args.toString() + ")";
   }

   private ReflectionUtility() {
   }
}
